package com.kevin.testcamera;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.FrameLayout;
import android.app.Activity;
import android.content.Context;

public class MainActivity extends Activity implements SensorEventListener {
	private final String TAG = "MainActivity";
	private CameraPerview mPerview;
	private Camera mCamera;
	private boolean mIsRecording = false;
	private MediaRecorder mMediaRecorder;

	private final static float MIN_ACCEL_TO_STRIE_AUTOFOCUS = 1.0f;
	private SensorManager mSensorManager;
	private Sensor mAccel;
	private float mLastXAccel = 0;
	private float mLastYAccel = 0;
	private float mLastZAccel = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);

		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	}

	private Camera getCameraInstance() {
		Camera c = null;

		try {
			c = Camera.open();
		} catch (Exception e) {
			Log.e(TAG, "Error open camera: " + e.getMessage());
		}
		return c;
	}

	@Override
	protected void onResume() {
		initCamera();
		initPreview();

		mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_UI);
		super.onResume();
	}

	@Override
	protected void onPause() {
		mSensorManager.unregisterListener(this);
		
		releaseCamera();
		releasePerview();
		super.onPause();
	}

	private void initCamera() {
		if (null == mCamera) {
			mCamera = getCameraInstance();

			Parameters parameters = mCamera.getParameters();
			parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);

			mCamera.setDisplayOrientation(90);
		}
	}

	private void initPreview() {
		if (null != mCamera && null == mPerview) {
			mPerview = new CameraPerview(MainActivity.this, mCamera);
			FrameLayout preview = (FrameLayout) findViewById(R.id.camera_perview);
			preview.addView(mPerview);
		}
	}

	private void releaseCamera() {
		if (null != mCamera) {
			mCamera.release();
			mCamera = null;
		}
	}

	private void releasePerview() {
		FrameLayout preview = (FrameLayout) findViewById(R.id.camera_perview);
		preview.removeView(mPerview);
		mPerview = null;
	}

	public void onClkCapture(View view) {
		if (null != mCamera) {
			mCamera.takePicture(null, null, mPictureCallback);
		}
	}

	private PictureCallback mPictureCallback = new Camera.PictureCallback() {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			File picFile = getOutputMediaFile();
			try {
				FileOutputStream fos = new FileOutputStream(picFile);
				fos.write(data);
				fos.close();
			} catch (FileNotFoundException e) {
				Log.d(TAG, "file not found ");
			} catch (IOException e) {
				Log.d(TAG, "write failed");
			}
		}

		private File getOutputMediaFile() {
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
			String str = dateFormat.format(new Date(System.currentTimeMillis())) + ".jpg";
			File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), str);
			return file;
		}
	};

	public void onClkRecord(View view) {
		if (false == mIsRecording) {
			if (perparingRecord()) {
				mMediaRecorder.start();
				mIsRecording = true;
				setTextOfRecordButton("stop");
			} else {
				releaseMediaRecorder();
			}
		} else {
			stopRecord();
			releaseMediaRecorder();
			mIsRecording = false;
			setTextOfRecordButton("record");
		}
	}

	private void setTextOfRecordButton(String str) {
		Button btnRecord = (Button) findViewById(R.id.btn_record);
		btnRecord.setText(str);
	}

	private boolean perparingRecord() {
		// 1. unlock the camera
		mCamera.unlock();

		// 2. configure the mMediaRecorder
		mMediaRecorder = new MediaRecorder();
		mMediaRecorder.setCamera(mCamera);
		mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
		mMediaRecorder.setOutputFile(getOutputVideoFile().getPath());
		mMediaRecorder.setPreviewDisplay(mPerview.getHolder().getSurface());

		// 3. prepare configured mMediaRecorder
		try {
			mMediaRecorder.prepare();
		} catch (IllegalStateException e) {
			Log.e(TAG, "Illegal state preparing mediaRecorder: " + e.getMessage());
			return false;
		} catch (IOException e) {
			Log.e(TAG, "IOException perparing mediaRecorder: " + e.getMessage());
			return false;
		}

		return true;
	}

	private File getOutputVideoFile() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
		String str = dateFormat.format(new Date(System.currentTimeMillis())) + ".mp4";
		File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), str);
		return file;
	}

	private void stopRecord() {
		if (null != mMediaRecorder) {
			mMediaRecorder.stop();
		}
	}

	private void releaseMediaRecorder() {
		if (null != mMediaRecorder) {
			mMediaRecorder.reset();
			mMediaRecorder.release();
			mMediaRecorder = null;
			mCamera.lock();
		}
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		float x = event.values[0];
		float y = event.values[1];
		float z = event.values[2];

		if (Math.abs(mLastXAccel - x) > MIN_ACCEL_TO_STRIE_AUTOFOCUS ||
			Math.abs(mLastYAccel - y) > MIN_ACCEL_TO_STRIE_AUTOFOCUS ||
			Math.abs(mLastZAccel - z) > MIN_ACCEL_TO_STRIE_AUTOFOCUS) {
			if (null != mCamera) {
				try {
					mCamera.autoFocus(null);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		mLastXAccel = x;
		mLastYAccel = y;
		mLastZAccel = z;
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {

	}
}
